home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / polyray / util / ttfx.c < prev    next >
C/C++ Source or Header  |  1994-03-15  |  30KB  |  937 lines

  1. /* TrueType font file processing */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <math.h>
  7.  
  8. #if defined(MAC)
  9. #include <console.h>
  10. #define FSCFG_BIG_ENDIAN
  11. #else
  12. #define PC_OS
  13. #endif
  14.  
  15. #ifndef SEEK_SET
  16. #define SEEK_SET        0       /* seek from start of file      */
  17. #define SEEK_CUR        1       /* relative to current position */
  18. #define SEEK_END        2       /* relative to end of file      */
  19. #endif
  20.  
  21. #define EPSILON 1.0e-10
  22. #define MAX_ITERATIONS 50
  23. #define COEFF_LIMIT 1.0e-20
  24.  
  25. #define ONCURVE             0x01
  26. #define XSHORT              0x02
  27. #define YSHORT              0x04
  28. #define REPEAT_FLAGS        0x08 /* repeat flag n times */
  29. #define SHORT_X_IS_POS      0x10 /* the short vector is positive */
  30. #define NEXT_X_IS_ZERO      0x10 /* the relative x coordinate is zero */
  31. #define SHORT_Y_IS_POS      0x20 /* the short vector is positive */
  32. #define NEXT_Y_IS_ZERO      0x20 /* the relative y coordinate is zero */
  33.  
  34. typedef char int8;
  35. typedef unsigned char uint8;
  36. typedef short int16;
  37. typedef unsigned short uint16;
  38. typedef long int32;
  39. typedef unsigned long uint32;
  40.  
  41. typedef short FUnit;
  42. typedef unsigned short uFUnit;
  43.  
  44. #ifdef PC_OS
  45. typedef long Fixed;
  46. #endif
  47.  
  48. #ifndef FAR 
  49. #define FAR 
  50. #endif 
  51.  
  52. #ifndef NEAR 
  53. #define NEAR 
  54. #endif 
  55.  
  56. #if defined(FSCFG_BIG_ENDIAN)
  57. /* target byte order matches Motorola 68000 */
  58. #define SWAPL(a)        (a)
  59. #define SWAPW(a)        (a)
  60. #else
  61. /* Macros to turn little endian words/longs into big endian words/longs */
  62. #define FS_2BYTE(p)  (((unsigned short)((p)[0]) << 8) |  (p)[1])
  63. #define FS_4BYTE(p)  (FS_2BYTE((p)+2) | ( (FS_2BYTE(p)+0L) << 16))
  64. #define SWAPW(a) ((short) FS_2BYTE((unsigned char FAR *)(&a)))
  65. #define SWAPL(a) ((long) FS_4BYTE((unsigned char FAR *)(&a)))
  66. #endif
  67.  
  68. /* Constants defined in Motorola order (use SWAPL to correct) */
  69. static uint32 tag_CharToIndexMap = 0x636d6170; /* 'cmap' */
  70. static uint32 tag_FontHeader     = 0x68656164; /* 'head' */
  71. static uint32 tag_GlyphData      = 0x676c7966; /* 'glyf' */
  72. static uint32 tag_IndexToLoc     = 0x6c6f6361; /* 'loca' */
  73. static uint32 tag_Kerning        = 0x6b65726e; /* 'kern' */
  74. static uint32 tag_MaxProfile     = 0x6d617870; /* 'maxp' */
  75.  
  76. typedef struct {
  77.    uint32 bc;
  78.    uint32 ad;
  79.    } BigDate;
  80.  
  81. typedef struct {
  82.    int32  tag;
  83.    uint32 checkSum;
  84.    uint32 offset;
  85.    uint32 length;
  86.    } sfnt_DirectoryEntry;
  87.  
  88. typedef struct {
  89.    int32 version;                  /* 0x10000 (1.0) */
  90.    uint16 numOffsets;              /* number of tables */
  91.    uint16 searchRange;             /* (max2 <= numOffsets)*16 */
  92.    uint16 entrySelector;           /* log2 (max2 <= numOffsets) */
  93.    uint16 rangeShift;              /* numOffsets*16-searchRange*/
  94.    sfnt_DirectoryEntry table[1];   /* table[numOffsets] */
  95.    } sfnt_OffsetTable;
  96.  
  97. typedef struct {
  98.    Fixed       version;            /* for this table, set to 1.0 */
  99.    Fixed       fontRevision;       /* For Font Manufacturer */
  100.    uint32      checkSumAdjustment;
  101.    uint32      magicNumber;        /* signature, must be 0x5F0F3CF5 == MAGIC */
  102.    uint16      flags;
  103.    uint16      unitsPerEm;         /* How many in Font Units per EM */
  104.  
  105.    BigDate     created;
  106.    BigDate     modified;
  107.  
  108.    /** This is the font wide bounding box in ideal space
  109.        (baselines and metrics are NOT worked into these numbers) **/
  110.    FUnit       xMin;
  111.    FUnit       yMin;
  112.    FUnit       xMax;
  113.    FUnit       yMax;
  114.  
  115.    uint16      macStyle;               /* macintosh style word */
  116.    uint16      lowestRecPPEM;          /* lowest recommended pixels per Em */
  117.  
  118.    /* 0: fully mixed directional glyphs,
  119.       1: only strongly L->R or T->B glyphs, 
  120.      -1: only strongly R->L or B->T glyphs,
  121.       2: like 1 but also contains neutrals,
  122.      -2: like -1 but also contains neutrals */
  123.    int16       fontDirectionHint;
  124.  
  125.    int16       indexToLocFormat;
  126.    int16       glyphDataFormat;
  127.    } sfnt_FontHeader;
  128.  
  129. typedef struct {
  130.    uint16  format;
  131.    uint16  length;
  132.    uint16  version;
  133.    } sfnt_mappingTable;
  134.  
  135. typedef struct {
  136.    uint16  platformID;
  137.    uint16  specificID;
  138.    uint32  offset;
  139.    } sfnt_platformEntry;
  140.  
  141. typedef sfnt_platformEntry FAR *sfnt_platformEntryPtr;
  142. typedef sfnt_DirectoryEntry FAR *sfnt_DirectoryEntryPtr;
  143.  
  144. typedef struct {
  145.     int16 numContours;
  146.     int16 xMin;
  147.     int16 yMin;
  148.     int16 xMax;
  149.     int16 yMax;
  150.     } GlyphHeader;
  151.  
  152. typedef struct {
  153.    GlyphHeader header;
  154.    uint16 numPoints;
  155.    uint16 *endPoints;
  156.    uint8  *flags;
  157.    float  *x, *y;
  158.    } GlyphOutline;
  159.  
  160. typedef struct {
  161.    uint8 inside_flag;  /* 1 if this an inside contour, 0 if outside */
  162.    uint16 count;       /* Number of points in the contour */
  163.    uint8  *flags;      /* On/off curve flags */
  164.    float  *x, *y;      /* Coordinates of control vertices */
  165.    } Contour;
  166.  
  167. typedef struct FontFileInfoStruct *FontFileInfoPtr;
  168. typedef struct GlyphStruct *GlyphPtr;
  169.  
  170. /* Contour information for a single glyph */
  171. typedef struct GlyphStruct {
  172.    GlyphHeader header;     /* Count and sizing information about this glyph */
  173.    uint16 glyph_index;     /* Internal glyph index for this character */
  174.    Contour *contours;      /* Array of outline contours */
  175.    FontFileInfoPtr parent; /* Parent font for this glyph */
  176.    GlyphPtr next;          /* Next cached glyph */
  177.    char   c;               /* Character code */
  178.    } Glyph;
  179.  
  180. /* Useful general data about this font */
  181. typedef struct FontFileInfoStruct {
  182.    char *filename;
  183.    FILE *fp;
  184.    uint16 numGlyphs;
  185.    uint16 unitsPerEm;
  186.    int16  loca_format;
  187.    uint32 *loca_table;
  188.    uint32 loca_table_offset;
  189.    uint32 cmap_table_offset;
  190.    uint32 glyph_table_offset;
  191.    GlyphPtr glyphs;                   /* Cached info for this font */
  192.    struct FontFileInfoStruct *next; /* Next font */
  193.    } FontFileInfo;
  194.  
  195. static FontFileInfo *TTFonts = NULL;
  196.  
  197. static FontFileInfo *
  198. OpenFontFile(char *filename)
  199. {
  200.    int i;
  201.    FontFileInfo *fontlist;
  202.  
  203.    /* First look to see if we have already opened this font */
  204.    for (fontlist = TTFonts;fontlist!=NULL;fontlist=fontlist->next)
  205.       if (!strcmp(filename, fontlist->filename))
  206.          break;
  207.  
  208.    if (fontlist != NULL) {
  209.       /* We have a match, use the previous information */
  210.       if ((fontlist->fp == NULL) &&
  211.           (fontlist->fp = fopen(fontlist->filename, "rb")) == NULL) {
  212.          fprintf(stderr, "Can't open font file: '%s'\n",
  213.                  fontlist->filename);
  214.          exit(1);
  215.          }
  216.       }
  217.    else {
  218.       /* We haven't looked at this font before, let's allocate a
  219.          holder for the information and set some defaults */
  220.       fontlist = malloc(sizeof(FontFileInfo));
  221.       if (fontlist == NULL) {
  222.          fprintf(stderr, "Out of memory\n");
  223.          exit(1);
  224.          }
  225.       i = strlen(filename) + 1;
  226.       fontlist->filename = malloc(i * sizeof(char));
  227.       strcpy(fontlist->filename, filename);
  228.       if ((fontlist->fp = fopen(fontlist->filename, "rb")) == NULL) {
  229.          fprintf(stderr, "Can't open font file: '%s'\n",
  230.                  fontlist->filename);
  231.          exit(1);
  232.          }
  233.       fontlist->numGlyphs = 0;
  234.       fontlist->unitsPerEm = 16384;
  235.       fontlist->loca_format = 0;
  236.       fontlist->loca_table_offset = 0;
  237.       fontlist->loca_table = NULL;
  238.       fontlist->cmap_table_offset = 0;
  239.       fontlist->glyph_table_offset = 0;
  240.       fontlist->glyphs = NULL;
  241.       fontlist->next = NULL;
  242.       }
  243.  
  244.    return fontlist;
  245. }
  246.  
  247. static void
  248. FreeFontInfo()
  249. {
  250.    int i;
  251.    FontFileInfo *oldfont, *tempfont;
  252.    GlyphPtr glyphs, tempglyph;
  253.  
  254.    for (oldfont=TTFonts;oldfont!=NULL;) {
  255.       if (oldfont->fp != NULL)
  256.          fclose(oldfont->fp);
  257.       free(oldfont->filename);
  258.       if (oldfont->loca_table != NULL)
  259.          free(oldfont->loca_table);
  260.       for (glyphs=oldfont->glyphs;glyphs!=NULL;) {
  261.          for (i=0;i<glyphs->header.numContours;i++) {
  262.             free(glyphs->contours[i].flags);
  263.             free(glyphs->contours[i].x);
  264.             free(glyphs->contours[i].y);
  265.             }
  266.          free(glyphs->contours);
  267.          tempglyph = glyphs;
  268.          glyphs = glyphs->next;
  269.          free(tempglyph);
  270.          }
  271.       tempfont = oldfont;
  272.       oldfont = oldfont->next;
  273.       free(tempfont);
  274.       }
  275.    TTFonts = NULL;
  276. }
  277.  
  278. /* Transform a glyph from TrueType storage format to something a little
  279.    easier to manage */
  280. static GlyphPtr
  281. ConvertOutlineToGlyph(FontFileInfo *ffile, GlyphOutline *ttglyph)
  282. {
  283.    GlyphPtr glyph;
  284.    float *temp_x, *temp_y;
  285.    uint8 *temp_f;
  286.    uint16 i, j, last_j;
  287.  
  288.    /* Create storage for this glyph */
  289.    if ((glyph = malloc(sizeof(Glyph))) == NULL)
  290.       exit(1);
  291.    glyph->contours = malloc(ttglyph->header.numContours * sizeof(Contour));
  292.    if (glyph->contours == NULL)
  293.       exit(1);
  294.  
  295.    /* Copy sizing information about this glyph */
  296.    memcpy(&glyph->header, &ttglyph->header, sizeof(GlyphHeader));
  297.  
  298.    /* Keep track of the parent font for this glyph */
  299.    glyph->parent = ffile;
  300.  
  301.    /* Now copy the vertex information into the contours */
  302.    for (i=0, last_j=0;i<ttglyph->header.numContours;i++) {
  303.       /* Figure out number of points in contour */
  304.       j = ttglyph->endPoints[i] - last_j + 1;
  305.  
  306.       /* Copy the coordinate information into the glyph */
  307.       temp_x = malloc((j+1) * sizeof(float));
  308.       temp_y = malloc((j+1) * sizeof(float));
  309.       temp_f = malloc((j+1) * sizeof(uint8));
  310.       if (temp_x == NULL || temp_y == NULL || temp_f == NULL)
  311.          exit(1);
  312.       memcpy(temp_x, &ttglyph->x[last_j], j * sizeof(float));
  313.       memcpy(temp_y, &ttglyph->y[last_j], j * sizeof(float));
  314.       memcpy(temp_f, &ttglyph->flags[last_j], j * sizeof(uint8));
  315.       temp_x[j] = ttglyph->x[last_j];
  316.       temp_y[j] = ttglyph->y[last_j];
  317.       temp_f[j] = ttglyph->flags[last_j];
  318.  
  319.       /* Figure out if this is an inside or outside contour */
  320.       glyph->contours[i].inside_flag = 0;
  321.  
  322.       /* Plug in the reset of the contour components into the glyph */
  323.       glyph->contours[i].count = j;
  324.       glyph->contours[i].x = temp_x;
  325.       glyph->contours[i].y = temp_y;
  326.       glyph->contours[i].flags = temp_f;
  327.  
  328.       /* Set last_j to point to the beginning of the next contour's
  329.          coordinate information */
  330.       last_j = ttglyph->endPoints[i] + 1;
  331.       }
  332.  
  333. /* Show statistics about this glyph */
  334. /*
  335. printf("Number of contours: %u\n",
  336.        glyph->header.numContours);
  337. printf("X extent: [%f, %f]\n",
  338.        (float)glyph->header.xMin / (float)glyph->parent->unitsPerEm,
  339.        (float)glyph->header.xMax / (float)glyph->parent->unitsPerEm);
  340. printf("Y extent: [%f, %f]\n",
  341.        (float)glyph->header.yMin / (float)glyph->parent->unitsPerEm,
  342.        (float)glyph->header.yMax / (float)glyph->parent->unitsPerEm);
  343. printf("Converted coord list(%d):\n", (int)glyph->header.numContours);
  344. for (i=0;i<glyph->header.numContours;i++) {
  345.    for (j=0;j<=glyph->contours[i].count;j++)
  346.       printf("  %c[%f, %f]\n",
  347.              (glyph->contours[i].flags[j] & ONCURVE ? '*' : ' '),
  348.              glyph->contours[i].x[j], glyph->contours[i].y[j]);
  349.    printf("\n");
  350.    }
  351. */
  352.  
  353.    return glyph;
  354. }
  355.  
  356. /* Read the contour information for a specific glyph */
  357. static GlyphPtr
  358. ExtractGlyphInfo(FontFileInfo *ffile, uint16 glyph_index, unsigned char c)
  359. {
  360.    int i, j;
  361.    uint8 temp8, flag, repeat_count;
  362.    uint16 temp16, n, nc;
  363.    int16 coord, itemp16;
  364.    Fixed tempF;
  365.    GlyphOutline *ttglyph;
  366.    GlyphPtr glyph;
  367.  
  368.    if ((ttglyph = malloc(sizeof(GlyphOutline))) == NULL) {
  369.       fprintf(stderr, "Out of memory\n");
  370.       exit(1);
  371.       }
  372.  
  373.    fseek(ffile->fp, ffile->glyph_table_offset +
  374.                     ffile->loca_table[glyph_index], SEEK_SET);
  375.    fread(&ttglyph->header, 1, sizeof(GlyphHeader), ffile->fp);
  376.    ttglyph->header.numContours = SWAPW(ttglyph->header.numContours);
  377.    ttglyph->header.xMax        = SWAPW(ttglyph->header.xMax);
  378.    ttglyph->header.yMax        = SWAPW(ttglyph->header.yMax);
  379.    ttglyph->header.xMin        = SWAPW(ttglyph->header.xMin);
  380.    ttglyph->header.yMin        = SWAPW(ttglyph->header.yMin);
  381.  
  382.    nc = ttglyph->header.numContours;
  383.    if (nc > 0) {
  384.       /* Grab the contour endpoints */
  385.       if ((ttglyph->endPoints = malloc(nc * sizeof(uint16))) == NULL) {
  386.          fprintf(stderr, "Out of memory\n");
  387.          exit(1);
  388.          }
  389.       for (i=0;i<nc;i++) {
  390.          fread(&temp16, 1, sizeof(temp16), ffile->fp);
  391.          ttglyph->endPoints[i] = SWAPW(temp16);
  392.          }
  393.  
  394.       /* Skip over the instructions */
  395.       fread(&temp16, 1, sizeof(temp16), ffile->fp);
  396.       fseek(ffile->fp, SWAPW(temp16), SEEK_CUR);
  397.  
  398.       /* Determine the number of points making up this glyph */
  399.       n = ttglyph->numPoints = ttglyph->endPoints[nc-1] + 1;
  400.  
  401.       /* Read the flags */
  402.       if ((ttglyph->flags = malloc(n * sizeof(uint8))) == NULL) {
  403.          fprintf(stderr, "Out of memory\n");
  404.          exit(1);
  405.          }
  406.       for (i=0;i<ttglyph->numPoints;i++) {
  407.          fread(&ttglyph->flags[i], 1, 1, ffile->fp);
  408.          if (ttglyph->flags[i] & REPEAT_FLAGS) {
  409.             fread(&repeat_count, 1, 1, ffile->fp);
  410.             for (;repeat_count>0;repeat_count--,i++) {
  411.                ttglyph->flags[i+1] = ttglyph->flags[i];
  412.                }
  413.             }
  414.          }
  415.  
  416.       /* Read the coordinate vectors */
  417.       if ((ttglyph->x = malloc(n * sizeof(float))) == NULL ||
  418.           (ttglyph->y = malloc(n * sizeof(float))) == NULL) {
  419.          fprintf(stderr, "Out of memory\n");
  420.          exit(1);
  421.          }
  422.       coord = 0;
  423.       for (i=0;i<ttglyph->numPoints;i++) {
  424.          /* Read each x coordinate */
  425.          flag = ttglyph->flags[i];
  426.          if (flag & XSHORT) {
  427.             fread(&temp8, 1, 1, ffile->fp);
  428.             if (flag & SHORT_X_IS_POS)
  429.                coord += temp8;
  430.             else
  431.                coord -= temp8;
  432.             }
  433.          else if (!(flag & NEXT_X_IS_ZERO)) {
  434.             fread(&itemp16, 1, 2, ffile->fp);
  435.             coord += SWAPW(itemp16);
  436.             }
  437.          ttglyph->x[i] = (float)coord / (float)ffile->unitsPerEm;
  438.          }
  439.  
  440.       coord = 0;
  441.       for (i=0;i<ttglyph->numPoints;i++) {
  442.          /* Read each y coordinate */
  443.          flag = ttglyph->flags[i];
  444.          if (flag & YSHORT) {
  445.             fread(&temp8, 1, 1, ffile->fp);
  446.             if (flag & SHORT_Y_IS_POS)
  447.                coord += temp8;
  448.             else
  449.                coord -= temp8;
  450.             }
  451.          else if (!(flag & NEXT_Y_IS_ZERO)) {
  452.             fread(&itemp16, 1, 2, ffile->fp);
  453.             coord += SWAPW(itemp16);
  454.             }
  455.          ttglyph->y[i] = (float)coord / (float)ffile->unitsPerEm;
  456.          }
  457.  
  458.       /* Convert the glyph outline information from TrueType layout
  459.          into a more easily processed format */
  460.       glyph = ConvertOutlineToGlyph(ffile, ttglyph);
  461.       glyph->c = c;
  462.       glyph->glyph_index = glyph_index;
  463.  
  464.       /* Free up outline information */
  465.       free(ttglyph->y);
  466.       free(ttglyph->x);
  467.       free(ttglyph->endPoints);
  468.       free(ttglyph->flags);
  469.       }
  470.    else if (nc == 0) {
  471.       /* Do nothing */
  472.       }
  473.    else {
  474.       printf("Can't handle multiple component glyphs\n");
  475.       }
  476.  
  477.    return glyph;
  478. }
  479.  
  480. /* The file pointer must be pointing immediately after the version entry
  481.    in the encoding table for the next two functions to work. */
  482. static uint16
  483. ProcessFormat0Glyph(FILE *fp, unsigned char search_char)
  484. {
  485.    uint8 temp_index;
  486.  
  487.    fseek(fp, search_char, SEEK_CUR);
  488.    fread(&temp_index, 1, 1, fp); /* Each index is exactly 1 byte */
  489.    return (uint16)temp_index;
  490. }
  491.  
  492. static uint16
  493. ProcessFormat4Glyph(FILE *fp, unsigned char search_char)
  494. {
  495.    int i;
  496.    uint16  glyph_index;
  497.    long glyphIDoffset;
  498.    uint16 temp16;
  499.    uint16 segCount, searchRange, entrySelector, rangeShift;
  500.    uint16 *endCount, *startCount, *idDelta, *idRangeOffset;
  501.  
  502.    fread(&temp16, 1, sizeof(uint16), fp);
  503.    segCount = SWAPW(temp16) >> 1;
  504.    fread(&temp16, 1, sizeof(uint16), fp);
  505.    searchRange = SWAPW(temp16);
  506.    fread(&temp16, 1, sizeof(uint16), fp);
  507.    entrySelector = SWAPW(temp16);
  508.    fread(&temp16, 1, sizeof(uint16), fp);
  509.    rangeShift = SWAPW(temp16);
  510.  
  511.    /* Now allocate and read in the segment arrays */
  512.    endCount      = malloc(segCount * sizeof(uint16));
  513.    startCount    = malloc(segCount * sizeof(uint16));
  514.    idDelta       = malloc(segCount * sizeof(uint16));
  515.    idRangeOffset = malloc(segCount * sizeof(uint16));
  516.    if (endCount == NULL || startCount == NULL || idDelta == NULL ||
  517.        idRangeOffset == NULL) {
  518.       fprintf(stderr, "Out of memory\n");
  519.       exit(1);
  520.       }
  521.    for (i=0;i<segCount;i++) {
  522.       fread(&temp16, 1, sizeof(uint16), fp);
  523.       endCount[i] = SWAPW(temp16);
  524.       }
  525.    fread(&temp16, 1, sizeof(uint16), fp); /* Skip over 'reservedPad' */
  526.    for (i=0;i<segCount;i++) {
  527.       fread(&temp16, 1, sizeof(uint16), fp);
  528.       startCount[i] = SWAPW(temp16);
  529.       }
  530.    for (i=0;i<segCount;i++) {
  531.       fread(&temp16, 1, sizeof(uint16), fp);
  532.       idDelta[i] = SWAPW(temp16);
  533.       }
  534.    glyphIDoffset = ftell(fp);
  535.    for (i=0;i<segCount;i++) {
  536.       fread(&temp16, 1, sizeof(uint16), fp);
  537.       idRangeOffset[i] = SWAPW(temp16);
  538.       }
  539.  
  540.    /* Now search the segments for our character */
  541.    glyph_index = 0;
  542.    for (i=0;i<segCount;i++) {
  543.       if ((uint8)search_char <= endCount[i]) {
  544.          if ((uint8)search_char > startCount[i]) {
  545.             /* Found mapping */
  546.             if (idRangeOffset[i] == 0)
  547.                glyph_index = (uint16)search_char + idDelta[i];
  548.             else {
  549.                /* Alternate encoding of glyph indices, relies on a quite
  550.                   unusual way of storing the offsets.  Not really sure about
  551.                   the division by 2 on idRangeOffset, but the Microsoft
  552.                   manual seemed to do it that way. */
  553.                glyphIDoffset += i * sizeof(uint16) + idRangeOffset[i]/2 +
  554.                                 (search_char - startCount[i]);
  555.                fseek(fp, glyphIDoffset, SEEK_SET);
  556.                fread(&temp16, 1, sizeof(uint16), fp);
  557.                glyph_index = SWAPW(temp16);
  558.                if (glyph_index != 0)
  559.                   glyph_index = glyph_index + idDelta[i];
  560.                }
  561.             }
  562.          break;
  563.          }
  564.       }
  565.  
  566.    /* Deallocate the memory we used for the segment arrays */
  567.    free(endCount);
  568.    free(startCount);
  569.    free(idDelta);
  570.    free(idRangeOffset);
  571.  
  572.    return glyph_index;
  573. }
  574.  
  575. /* Trimmed table mapping */
  576. static uint16
  577. ProcessFormat6Glyph(FILE *fp, unsigned char search_char)
  578. {
  579.    uint16 temp16, firstCode, entryCount;
  580.    uint8 glyph_index;
  581.  
  582.    fread(&temp16, 1, 2, fp);
  583.    firstCode = SWAPW(temp16);
  584.    fread(&temp16, 1, 2, fp);
  585.    entryCount = SWAPW(temp16);
  586.    if (search_char >= firstCode && search_char < firstCode + entryCount) {
  587.       fseek(fp, search_char - firstCode, SEEK_CUR);
  588.       fread(&temp16, 1, 2, fp);
  589.       glyph_index = SWAPW(temp16);
  590.       }
  591.    else
  592.       glyph_index = 0;
  593.    return glyph_index;
  594. }
  595.  
  596.  
  597. /* find the character mapping for 'search_char' */
  598. static uint16
  599. ProcessCharMap(FontFileInfo *ffile, unsigned char search_char)
  600. {
  601.    long old_table_offset;
  602.    uint16 glyph_index, temp16;
  603.    uint16 entry_ID, entry_EID;
  604.    uint32 entry_offset;
  605.    sfnt_platformEntry cmapEntry;
  606.    sfnt_mappingTable encodingTable;
  607.    int i, table_count;
  608.  
  609.    /* Move to the start of the character map, skipping over the format
  610.       entry, right to the number of entries. */
  611.    fseek(ffile->fp, ffile->cmap_table_offset + sizeof(uint16), SEEK_SET);
  612.    fread(&temp16, 1, sizeof(uint16), ffile->fp);
  613.    table_count = SWAPW(temp16);
  614.  
  615.    /* Search the tables until we find the glyph index for the search
  616.       character.  Just return the first one we find... */
  617.    for (i=0;i<table_count;i++) {
  618.       fread(&cmapEntry, 1, sizeof(cmapEntry), ffile->fp);
  619.       entry_ID     = SWAPW(cmapEntry.platformID);
  620.       entry_EID    = SWAPW(cmapEntry.specificID);
  621.       entry_offset = SWAPL(cmapEntry.offset);
  622.       old_table_offset = ftell(ffile->fp);
  623.  
  624.       fseek(ffile->fp, ffile->cmap_table_offset + entry_offset, SEEK_SET);
  625.       fread(&encodingTable, 1, sizeof(encodingTable), ffile->fp);
  626.       /*
  627.       printf("Encoding table, format: %u, length: %u, version: %u\n",
  628.              SWAPW(encodingTable.format),
  629.              SWAPW(encodingTable.length),
  630.              SWAPW(encodingTable.version));
  631.       */
  632.  
  633.       if (SWAPW(encodingTable.format) == 0) {
  634.          /* Translation is simple - add 'entry_char' to the start
  635.             of the table and grab what's there */
  636.          /* printf("Apple standard index mapping\n"); */
  637.          glyph_index = ProcessFormat0Glyph(ffile->fp, search_char);
  638.          }
  639.       else if (SWAPW(encodingTable.format) == 4) {
  640.          /* Microsoft UGL encoding */
  641.          /* printf("Microsoft standard index mapping\n"); */
  642.          glyph_index = ProcessFormat4Glyph(ffile->fp, search_char);
  643.          }
  644.       else if (SWAPW(encodingTable.format) == 6) {
  645.          /* printf("Trimmed table mapping\n"); */
  646.          glyph_index = ProcessFormat6Glyph(ffile->fp, search_char);
  647.          }
  648.       else
  649.          printf("Unsupported index mapping format: %u\n",
  650.                 SWAPW(encodingTable.format));
  651.  
  652.       return glyph_index;
  653.  
  654.       /* Go back to the set of table descriptions at the beginning of
  655.          the cmap table. */
  656.       fseek(ffile->fp, old_table_offset, SEEK_SET);
  657.       }
  658.  
  659.    /* No character mapping was found - very odd, we should really have
  660.       had the character in at least one table.  Perhaps getting here
  661.       means we didn't have any character mapping tables */
  662.    return 0;
  663. }
  664.  
  665. /* This routine determines the total number of glyphs in a TrueType file.
  666.    Necessary so that we can allocate the proper amount of storage for
  667.    the glyph location table.  */
  668. static void
  669. ProcessMaxpTable(FontFileInfo *ffile, sfnt_DirectoryEntry *Table)
  670. {
  671.    long old_fp_offset;
  672.    Fixed temp_fixed;
  673.    uint16 temp16;
  674.  
  675.    old_fp_offset = ftell(ffile->fp);
  676.    fseek(ffile->fp, SWAPL(Table->offset), SEEK_SET);
  677.    fread(&temp_fixed, 1, sizeof(temp_fixed), ffile->fp);
  678.    fread(&temp16, 1, sizeof(temp16), ffile->fp);
  679.    ffile->numGlyphs = SWAPW(temp16);
  680.    fseek(ffile->fp, old_fp_offset, SEEK_SET);
  681. }
  682.  
  683. /* Process the font header table */
  684. static void
  685. ProcessHeadTable(FontFileInfo *ffile, sfnt_DirectoryEntry *Table)
  686. {
  687.    long old_fp_offset;
  688.    sfnt_FontHeader fontHeader;
  689.  
  690.    old_fp_offset = ftell(ffile->fp);
  691.    fseek(ffile->fp, SWAPL(Table->offset), SEEK_SET);
  692.  
  693.    fread(&fontHeader, 1, sizeof(fontHeader), ffile->fp);
  694.    ffile->loca_format = SWAPW(fontHeader.indexToLocFormat);
  695.    ffile->unitsPerEm = SWAPW(fontHeader.unitsPerEm);
  696.  
  697.    /* Back to where we started */
  698.    fseek(ffile->fp, old_fp_offset, SEEK_SET);
  699. }
  700.  
  701. /* Determine the relative offsets of glyphs */
  702. static void
  703. ProcessLocaTable(FontFileInfo *ffile)
  704. {
  705.    int i;
  706.    uint16 temp16;
  707.    uint32 temp32;
  708.  
  709.    /* Move to location of table in file */
  710.    fseek(ffile->fp, ffile->loca_table_offset, SEEK_SET);
  711.  
  712.    /* Make sure we understand the size of the entries in the table */
  713.    ffile->loca_table = malloc((ffile->numGlyphs + 1) * sizeof(uint32));
  714.    if (ffile->loca_table == NULL) {
  715.       fprintf(stderr, "Out of memory\n");
  716.       exit(1);
  717.       }
  718.  
  719.    /* Now read and save the loca table */
  720.    for (i=0;i<ffile->numGlyphs;i++) {
  721.       if (ffile->loca_format == 0) {
  722.          fread(&temp16, 1, sizeof(uint16), ffile->fp);
  723.          ffile->loca_table[i] = (uint32)SWAPW(temp16) << 1;
  724.          }
  725.       else {
  726.          fread(&temp32, 1, sizeof(uint32), ffile->fp);
  727.          ffile->loca_table[i] = SWAPL(temp32);
  728.          }
  729.       }
  730. }
  731.  
  732. /* Gather information about a specific font.  The font file must
  733.    be opened prior to calling this routine. */
  734. static FontFileInfo *
  735. ProcessFontFile(char *fontfilename)
  736. {
  737.    unsigned i, c;
  738.    sfnt_OffsetTable OffsetTable;
  739.    sfnt_DirectoryEntry Table;
  740.    FontFileInfo *ffile;
  741.  
  742.    /* Open the font file */
  743.    ffile = OpenFontFile(fontfilename);
  744.  
  745.    /* Read the initial directory header on the TTF.  The numOffsets variable
  746.       tells us how many tables are present in this file. */
  747.    fread(&OffsetTable, 1, sizeof(OffsetTable) - sizeof(sfnt_DirectoryEntry),
  748.          ffile->fp);
  749.    c = (unsigned)SWAPW(OffsetTable.numOffsets);
  750.  
  751.    /* Process general font information and save it. */
  752.    for (i = 0; i < c && i < 40; i++) {
  753.       if (fread(&Table, 1, sizeof(Table), ffile->fp) != sizeof(Table)) {
  754.          printf("Read failed on table #%d\n", i);
  755.          exit(-1);
  756.          }
  757.       if (Table.tag == SWAPL(tag_CharToIndexMap))
  758.          ffile->cmap_table_offset = SWAPL(Table.offset);
  759.       else if (Table.tag == SWAPL(tag_MaxProfile))
  760.          ProcessMaxpTable(ffile, &Table);
  761.       else if (Table.tag == SWAPL(tag_IndexToLoc))
  762.          ffile->loca_table_offset = SWAPL(Table.offset);
  763.       else if (Table.tag == SWAPL(tag_FontHeader))
  764.          ProcessHeadTable(ffile, &Table);
  765.       else if (Table.tag == SWAPL(tag_GlyphData))
  766.          ffile->glyph_table_offset = SWAPL(Table.offset);
  767.       }
  768.  
  769.    /* Close the font file descriptor (don't want to waste them) */
  770.    fclose(ffile->fp);
  771.    ffile->fp = NULL;
  772.  
  773.    /* Return the information about this font */
  774.    return ffile;
  775. }
  776.  
  777.  
  778. static GlyphPtr
  779. ProcessCharacter(FontFileInfo *ffile, unsigned char search_char)
  780. {
  781.    uint16 glyph_index;
  782.    GlyphOutline *ttglyph;
  783.    GlyphPtr glyph;
  784.  
  785.    /* See if we have already processed this glyph */
  786.    if (ffile->glyphs != NULL) {
  787.       for (glyph=ffile->glyphs;glyph!=NULL;glyph=glyph->next)
  788.          if (glyph->c == search_char) {
  789.             /* Found it, no need to do any more work */
  790.             return glyph;
  791.             }
  792.       }
  793.       
  794.    /* Open the font file (if necessary) */
  795.    if ((ffile->fp == NULL) &&
  796.        (ffile->fp = fopen(ffile->filename, "rb")) == NULL) {
  797.       fprintf(stderr, "Can't open font file: '%s'\n", ffile->filename);
  798.       exit(1);
  799.       }
  800.  
  801.    /* Now go extract information about the search character */
  802.    if (ffile->numGlyphs > 0 && ffile->loca_table_offset > 0 &&
  803.        ffile->cmap_table_offset > 0 && ffile->glyph_table_offset > 0) {
  804.       /* We have enough information on the file layout to go look for
  805.          the information about the search character */
  806.       ProcessLocaTable(ffile);
  807.       glyph_index = ProcessCharMap(ffile, search_char);
  808.       glyph = ExtractGlyphInfo(ffile, glyph_index, search_char);
  809.  
  810.       /* Add this glyph to the ones we already know about */
  811.       glyph->next = ffile->glyphs;
  812.       ffile->glyphs = glyph;
  813.       }
  814.  
  815.    /* Close the font file */
  816.    fclose(ffile->fp);
  817.    ffile->fp = NULL;
  818.  
  819.    /* Glyph is all built */
  820.    return glyph;
  821. }
  822.  
  823. static void
  824. OutputPolyrayGlyph(FontFileInfo *ffile, Glyph *glyph, float offset)
  825. {
  826.    int i, j;
  827.  
  828.    printf("object { // Char: '%c'\n", (char)glyph->c);
  829.    printf("   glyph %u\n", glyph->header.numContours);
  830.    for (i=0;i<glyph->header.numContours;i++) {
  831.       printf("      contour %d, ", (int)glyph->contours[i].count);
  832.       for (j=0;j<glyph->contours[i].count;j++) {
  833.          printf("<%f, %f, %c>",
  834.                 glyph->contours[i].x[j] + offset, glyph->contours[i].y[j],
  835.                 (glyph->contours[i].flags[j] & ONCURVE ? '0' : '1'));
  836.          if (j < glyph->contours[i].count - 1) {
  837.             printf(", ");
  838.         if (j > 0 && !(j % 5))
  839.            printf("\n");
  840.         }
  841.          else
  842.             printf("\n");
  843.          }
  844.       }
  845. printf("   }\n");
  846. }
  847.  
  848. int
  849. main(int argc, char **argv) 
  850. {
  851.    FontFileInfo *ffile;
  852.    int i, slen;
  853.    unsigned char *search_string = NULL;
  854.    GlyphPtr glyph;
  855.    float toffset, offset;
  856.  
  857. #ifdef MAC
  858.    /* Special case for Macintosh - this command pulls up a
  859.       dialog that simulates a command line */
  860.    argc = ccommand(&argv);
  861. #endif
  862.  
  863.    if (argc < 2) {
  864.       printf("usage: ttfx *.ttf string [char offset]\n");
  865.       printf("e.g.\n");
  866.       printf("       ttfx arialb.ttf Foo 0.1\n");
  867.       printf("       ttfx \\windows\\system\\times.ttf Foo\n");
  868.       exit(-1);
  869.       }
  870.    else if (argc > 2) {
  871.       slen = strlen(argv[2]);
  872.       search_string = malloc((slen + 1) * sizeof(unsigned char));
  873.       for (i=0;i<=slen;i++)
  874.          search_string[i] = (unsigned char)argv[2][i];
  875.       if (argc > 3)
  876.          offset = atof(argv[3]);
  877.       else
  878.          offset = 0.0;
  879.       }
  880.    else {
  881.       slen = 1;
  882.       search_string = malloc(2 * sizeof(unsigned char));
  883.       search_string[0] = 'X';
  884.       search_string[1] = '\0';
  885.       offset = 0.0;
  886.       }
  887.  
  888.    /* Get general font info */
  889.    ffile = ProcessFontFile(argv[1]);
  890.  
  891.    printf("// Font: '%s'\n", ffile->filename);
  892.    if (slen > 1)
  893.       /* Need to create the string as the union of the glyphs that
  894.          make up each character in the string */
  895.       printf("object {\n");
  896.  
  897.    /* Get info about each character in the string */
  898.    for (i=0,toffset=0.0;i<slen;i++) {
  899.       glyph = ProcessCharacter(ffile, search_string[i]);
  900. /* printf("Kick: %f\n",
  901.       glyph->header.xMin / (float)glyph->parent->unitsPerEm); */
  902.       /* Align this character to x = 0 on the left */
  903.       toffset -= glyph->header.xMin / (float)glyph->parent->unitsPerEm;
  904.  
  905.       /* Additional spacing based on the kerning table could go right here */
  906.  
  907.       /* Now we convert the glyph into Polyray format */
  908.       OutputPolyrayGlyph(ffile, glyph, toffset);
  909.  
  910. /*
  911. printf("Bump: %f\n", offset +
  912.                 (glyph->header.xMax - glyph->header.xMin) /
  913.                    (float)glyph->parent->unitsPerEm);
  914. */
  915.       /* Adjust character spacing to account for the width of the character,
  916.          plus the user-specified character spacing */
  917.       toffset += offset +
  918.                 (glyph->header.xMax - glyph->header.xMin) /
  919.                    (float)glyph->parent->unitsPerEm;
  920.  
  921.       /* If this is a union, then need to emit the "+" character */
  922.       if (slen > 1 && i < slen - 1)
  923.          printf("+\n");
  924.       }
  925.  
  926.    /* Close up the union of glyphs */
  927.    if (slen > 1)
  928.       printf("   }\n");
  929.  
  930.    FreeFontInfo();
  931.  
  932.    if (search_string != NULL)
  933.       free(search_string);
  934.  
  935.    return 0;
  936. }
  937.